/*
 *  Copyright (c)  13.04.2007 Philipp Marx.
 *  Permission is granted to copy, distribute and/or modify this document
 *  under the terms of the GNU Free Documentation License, Version 1.2
 *  or any later version published by the Free Software Foundation;
 *  with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts.
 *  A copy of the license is included in the section entitled "GNU
 *  Free Documentation License".
 */

package de.smigfu.irc.handler;


/**
 * Utility-Method to process IRC-messages.
 *
 * @version $Revision$ $Date$
 *
 * @author Philipp Marx, last modified by $Author$
 */
class MessageProcessor {

   /** SPECIAL as declared in IRC-RFC. */
   static final String SPECIAL = "[\\[\\]\\\\`_\\^{|}]";
   
   /** DIGIT as declared in IRC-RFC. */
   static final String DIGIT = "[0-9]";
   
   /** HEX_DIGIT as declared in IRC-RFC. */
   static final String HEX_DIGIT = "(" + DIGIT + "|A|B|C|D|E|F)";
   
   /** LETTER as declared in IRC-RFC. */
   static final String LETTER = "[A-Za-z]";
   
   /** USER as declared in IRC-RFC. */
   static final String USER = "[^\u0000\\u000A\\u000D @]+";
   
   /** CHANNEL_ID as declared in IRC-RFC. */
   static final String CHANNEL_ID = "5([A-Z]|[0-9])";
   
   /** CHANNEL_STRING as declared in IRC-RFC. */
   static final String CHANNEL_STRING = "[^\u0000\u0007\\u000A\\u000D ,:]";
   
   /** MASK as declared in IRC-RFC. */
   static final String MASK = ".*";
   
   /** TARGET_MASK as declared in IRC-RFC. */
   static final String TARGET_MASK = "($|#)" + MASK;
   
   /** NICK_NAME as declared in IRC-RFC. */
   static final String NICK_NAME = "([A-Za-z]|" + SPECIAL + ")([A-Za-z0-9-]|" + SPECIAL + "){0,8}";
   
   /** IP4_ADR as declared in IRC-RFC. */
   static final String IP4_ADR = DIGIT + "{1,3}." + DIGIT + "{1,3}." + DIGIT + "{1,3}." + DIGIT + "{1,3}";
   
   /** HOST_ADR as declared in IRC-RFC. */
   static final String HOST_ADR = IP4_ADR;
   
   /** SHORT_NAME as declared in IRC-RFC. */
   static final String SHORT_NAME = "(" + LETTER + "|" + DIGIT + ")(" + LETTER + "|" + DIGIT + "|-)*(" + LETTER + "|" + DIGIT + ")*";
   
   /** HOST_NAME as declared in IRC-RFC. */
   static final String HOST_NAME = SHORT_NAME + "(\\." + SHORT_NAME + ")*";
   
   /** HOST as declared in IRC-RFC. */
   static final String HOST = "(" + HOST_NAME + "|" + HOST_ADR + ")";
   
   /** SERVER_NAME as declared in IRC-RFC. */
   static final String SERVER_NAME = HOST_NAME;
   
   /** CHANNEL as declared in IRC-RFC. */
   static final String CHANNEL = "(#|\\+|(!" + CHANNEL_ID + ")|&)" + CHANNEL_STRING + "(:" + CHANNEL_STRING + ")*";
   
   /** MSG_TO as declared in IRC-RFC. */
   static final String MSG_TO = "(" + CHANNEL + "|(" + USER + "(%" + HOST + ")?@" + SERVER_NAME + ")|(" + USER + "%" + HOST + ")|" + TARGET_MASK + "|" + NICK_NAME + "|(" + NICK_NAME + "!" + USER + "@" + HOST + "))";
   
   /** MSG_TARGET as declared in IRC-RFC. */
   static final String MSG_TARGET = MSG_TO + "(, " + MSG_TO + ")*";
   
   /** TARGET as declared in IRC-RFC. */
   static final String TARGET = "(" + NICK_NAME + "|" + SERVER_NAME + ")";
   
   /** COMMAND as declared in IRC-RFC. */
   static final String COMMAND = "((" + LETTER + ")+|(" + DIGIT + "){3})";
   
   /** PREFIX_NICKNAME as declared in IRC-RFC. */
   static final String PREFIX_NICKNAME = "(" + NICK_NAME + "((!" + USER + ")?@" + HOST + ")?)";
   
   /** PREFIX as declared in IRC-RFC. */
   static final String PREFIX = "(" + SERVER_NAME + "|" + PREFIX_NICKNAME + ")";

   /**
    * Extract the prefix, command and params. The returned <code>Array</code> has a length of 3
    * with each of the listed params.
    * 
    * @param msg The message.
    * @return The array with prefix, command and params.
    */
   static String[] extractMessageParts(String msg) {
      if (msg == null) {
         throw new IllegalArgumentException("message must not be NULL!");
      }

      String[] parts = new String[3];

      // A copy of the org. message. We use this to perform some String-ops.
      String msgCopy = msg;

      // Do we have a message Prefix.
      if (msgCopy.matches("^:" + PREFIX + " .*")) {

         // Extract and process the prefix.
         int prefixEnd = msgCopy.indexOf(" ");
         String prefix = msgCopy.substring(1, prefixEnd);
         parts[0] = prefix;
         msgCopy = msgCopy.substring(prefixEnd + 1);
      }

      // Extract the command.
      int cmdEnd = msgCopy.indexOf(" ");
      String cmd = msgCopy.substring(0, cmdEnd);
      parts[1] = cmd;
      msgCopy = msgCopy.substring(cmdEnd + 1);

      // Do we have parameters.
      if (msgCopy.length() > 0) {
         parts[2] = msgCopy;
      }

      return parts;
   }

   /**
    * Extracts the nickname from the given message-prefix (as evaluated by {@link #extractMessageParts(String)}.
    * If no nick is availabe <code>null</code> is returned.
    * 
    * @param prefix The prefix or <code>null</code>.
    * @return The nickname or <code>null</code>.
    */
   static String extractNickName(String prefix) {

      // prefix = servername / ( nickname [ [ "!" user ] "@" host ] )

      String nickName = null;

      if (prefix != null && prefix.matches(PREFIX_NICKNAME)) {
         int pmIx = prefix.indexOf("!");
         if (pmIx > 0) {
            nickName = prefix.substring(0, pmIx);
         } else {
            int atIx = prefix.indexOf("@");
            if (atIx > 0) {
               nickName = prefix.substring(0, atIx);
            } else {
               nickName = prefix;
            }
         }
      }

      return nickName;
   }
}
